#include "triangle.h"
#include <QDateTime>

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

const char *defaultVs =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;"
        "layout (location = 2) in vec2 aTexCoords;"

        "out vec2 TexCoords;"

        "uniform mat4 projection;"
        "uniform mat4 view;"
        "uniform mat4 model;"

        "void main()"
        "{"
        "    TexCoords = aTexCoords;"
        "    gl_Position = projection * view * model * vec4(aPos, 1.0);"
        "}";

const char *defaultFs =
        "#version 330 core\n"
        "out vec4 FragColor;"

        "in vec2 TexCoords;"

        "uniform sampler2D texture_diffuse1;"

        "void main()"
        "{"
        "    FragColor = texture(texture_diffuse1, TexCoords);"
        "}";

const char *normalVisualizationVs =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;"
        "layout (location = 1) in vec3 aNormal;"

        "out VS_OUT {"
        "    vec3 normal;"
        "} vs_out;"

        "uniform mat4 view;"
        "uniform mat4 model;"

        "void main()"
        "{"
        "    mat3 normalMatrix = mat3(transpose(inverse(view * model)));"
        "    vs_out.normal = vec3(vec4(normalMatrix * aNormal, 0.0));"
        "    gl_Position = view * model * vec4(aPos, 1.0); "
        "}";

const char *normalVisualizationFs =
        "#version 330 core\n"
        "out vec4 FragColor;"

        "void main()"
        "{"
        "    FragColor = vec4(1.0, 1.0, 0.0, 1.0);"
        "}";

const char *normalVisualizationGs =
        "#version 330 core\n"
        "layout (triangles) in;"
        "layout (line_strip, max_vertices = 6) out;"

        "in VS_OUT {"
        "    vec3 normal;"
        "} gs_in[];"

        "const float MAGNITUDE = 0.2;"

        "uniform mat4 projection;"

        "void GenerateLine(int index)"
        "{"
        "    gl_Position = projection * gl_in[index].gl_Position;"
        "    EmitVertex();"
        "    gl_Position = projection * (gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * MAGNITUDE);"
        "    EmitVertex();"
        "    EndPrimitive();"
        "}"

        "void main()"
        "{"
        "    GenerateLine(0);" // first vertex normal
        "    GenerateLine(1);" // second vertex normal
        "    GenerateLine(2);" // third vertex normal
        "}";


Triangle::Triangle(){

}

Triangle::~Triangle(){

}

void Triangle::initializeGL(){
    this->resize(1000,800);
    //着色器部分
    this->initializeOpenGLFunctions();
    // 监听键盘
    this->releaseKeyboard();

    // configure global opengl state
    // -----------------------------
    glEnable(GL_DEPTH_TEST);


    shader = std::make_shared<Shader>(this);
    normalVisualizationShader = std::make_shared<Shader>(this);

    shader->readShaderStr(defaultVs, defaultFs);
    normalVisualizationShader->readShaderStr(normalVisualizationVs, normalVisualizationFs, normalVisualizationGs);

    ourModel = std::make_shared<Model>("D:/Material/nanosuit/nanosuit.obj", this);

}

void Triangle::resizeGL(int w, int h){
    QExpandOpenGLWidget::resizeGL(w, h);
}

void Triangle::paintGL(){
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
    glm::mat4 model = glm::mat4(1.0f);
    shader->use();
    shader->setMat4("model", model);
    shader->setMat4("view", view);
    shader->setMat4("projection", projection);

    ourModel->Draw(*shader);

    // then draw model with normal visualizing geometry shader
    normalVisualizationShader->use();
    normalVisualizationShader->setMat4("projection", projection);
    normalVisualizationShader->setMat4("view", view);
    normalVisualizationShader->setMat4("model", model);

    ourModel->Draw(*normalVisualizationShader);

    glUseProgram(0);
    this->update();
}

void Triangle::keyPressEvent(QKeyEvent *event){
    QExpandOpenGLWidget::keyPressEvent(event);
}

void Triangle::mouseReleaseEvent(QMouseEvent* event){
    QExpandOpenGLWidget::mouseReleaseEvent(event);
}


void Triangle::mousePressEvent(QMouseEvent *event) {
    QExpandOpenGLWidget::mousePressEvent(event);
}

void Triangle::mouseMoveEvent(QMouseEvent* event){
    QExpandOpenGLWidget::mouseMoveEvent(event);
}


void Triangle::wheelEvent(QWheelEvent *event) {
    QExpandOpenGLWidget::wheelEvent(event);
}
